package com.yvon.maple.service.base.ffmpeg;

import com.yvon.maple.service.base.util.FileUtils;
import io.jsonwebtoken.lang.Assert;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;

/**
 * ffmpeg 工具类
 *
 * @author yvonwang
 * @date 2022/07/30
 */
@Slf4j
public class FfmpegUtils {

    //执行成功0,失败1
    private static Integer CODE_SUCCESS = 0;
    private static Integer CODE_FAIL = 1;

    private static String MP4 = ".mp4";

    private static String TS = ".ts";

    private static String TS_PRE = "_ts";

    private static String M3U8 = ".m3u8";

    private static String cmd_video_2_mp4 = "-i %s -y -c:v copy -c:a copy %s";

    private static String cmd_mp4_2_ts = " -y -i %s  -vcodec copy -acodec copy -vbsf h264_mp4toannexb %s ";

    private static String cmd_ts_split = " -i %s -c copy -map 0 -f segment -segment_list %s -segment_time 15";

    private static String TS_FILE = "_%3d.ts";



    public static String videoToMp4(String videoFile) {
        Assert.notNull(videoFile, "视频地址不能为空");
        if (videoFile.endsWith(MP4)) {
            return videoFile;
        }
        String mp4File = FileUtils.getFilePathMainName(videoFile).concat(MP4);
        String cmd = String.format(cmd_video_2_mp4, videoFile, mp4File);
        Integer code = cmdExec(cmd);
        Assert.isTrue(CODE_SUCCESS.equals(code), "视频转mp4失败");
        log.info("视频转mp4成功，mp4：[{}]", mp4File);
        deleteFile(videoFile);
        return mp4File;
    }

    public static String mp4ToTs(String mp4File) {
        Assert.notNull(mp4File, "mp4地址不能为空");
        String tsFile = FileUtils.getFilePathMainName(mp4File).concat(TS_PRE).concat(TS);
        String cmd = String.format(cmd_mp4_2_ts, mp4File, tsFile);
        Integer code = cmdExec(cmd);
        Assert.isTrue(CODE_SUCCESS.equals(code), "mp4转ts失败");
        log.info("mp4转ts成功，ts：[{}]", tsFile);
        deleteFile(mp4File);
        return tsFile;
    }

    public static String tsSpilt(String tsFile) {
        Assert.notNull(tsFile, "ts文件不能为空");
        String mainName = FileUtils.getFilePathMainName(tsFile.replaceAll(TS_PRE, ""));
        String m3u8 = mainName.concat(M3U8);

        String cmd = String.format(cmd_ts_split, tsFile, m3u8)+" ".concat(mainName).concat(TS_FILE);
        Integer code = cmdExec(cmd);
        Assert.isTrue(CODE_SUCCESS.equals(code), "ts切分失败");
        log.info("ts切分成功，m3u8：[{}]", m3u8);
        deleteFile(tsFile);
        return m3u8;
    }

    public static void deleteFile(String file) {
        File dest = new File(file);
        if (dest.isFile() && dest.exists()) {
            dest.delete();
            System.gc();
            log.warn("临时文件 {}已删除", dest.getName());
        }
    }

    /**
     * (执行ffmpeg自定义命令)
     */
    public static Integer cmdExec(String cmdStr) {
        //code=0表示正常
        Integer code  = null;
        FfmpegCmd ffmpegCmd = new FfmpegCmd();
        /**
         * 错误流
         */
        InputStream errorStream = null;
        try {
            //destroyOnRuntimeShutdown表示是否立即关闭Runtime
            //如果ffmpeg命令需要长时间执行，destroyOnRuntimeShutdown = false

            //openIOStreams表示是不是需要打开输入输出流:
            //	       inputStream = processWrapper.getInputStream();
            //	       outputStream = processWrapper.getOutputStream();
            //	       errorStream = processWrapper.getErrorStream();
            ffmpegCmd.execute(false, true, cmdStr);
            errorStream = ffmpegCmd.getErrorStream();

            //打印过程
            int len = 0;
            while ((len=errorStream.read())!=-1){
                System.out.print((char)len);
            }

            //code=0表示正常
            code = ffmpegCmd.getProcessExitCode();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭资源
            ffmpegCmd.close();
        }
        //返回
        return code;
    }

}
